#include <linux/err.h>
#include <linux/errno.h>
#include <linux/bug.h>
#include <linux/fs2.h>
#include <linux/pagemap.h>
#include <linux/mm_types.h>
#include <linux/radix-tree.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/uaccess.h>

int generic_segment_checks(const struct iovec *iov,
			unsigned long *nr_segs, size_t *count, int access_flags)
{
	unsigned long   seg;
	size_t cnt = 0;
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	for (seg = 0; seg < *nr_segs; seg++) {
		const struct iovec *iv = &iov[seg];

		/*
		 * If any segment has a negative length, or the cumulative
		 * length ever wraps negative then return -EINVAL.
		 */
		cnt += iv->iov_len;
		if ((ssize_t)(cnt|iv->iov_len) < 0)
			return -EINVAL;
		// if (access_ok(access_flags, iv->iov_base, iv->iov_len))
			continue;
		if (seg == 0)
			return -EFAULT;
		*nr_segs = seg;
		cnt -= iv->iov_len;	/* This segment is no good */
		break;
	}
	*count = cnt;
	return 0;
}

struct page *find_get_page(struct address_space *mapping, pgoff_t offset)
{
	void **pagep;
	struct page *page;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	// rcu_read_lock();
repeat:
	page = NULL;
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	pagep = radix_tree_lookup_slot(&mapping->page_tree, offset);
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	if (pagep) {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		page = radix_tree_deref_slot(pagep);
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		if (!page || page == RADIX_TREE_RETRY)
			goto repeat;

		printf("this is %s(): %d\r\n", __func__, __LINE__);

		// if (!page_cache_get_speculative(page))
		// 	goto repeat;

		/*
		 * Has the page moved?
		 * This is part of the lockless pagecache protocol. See
		 * include/linux/pagemap.h for details.
		 */
		if (page != *pagep) {
			printf("this is %s(): %d\r\n", __func__, __LINE__);
			// page_cache_release(page);
			goto repeat;
		}
	}
	// rcu_read_unlock();
	printf("this is %s(): %d\r\n", __func__, __LINE__);

	return page;
}

struct page *find_lock_page(struct address_space *mapping, pgoff_t offset)
{
	struct page *page;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

repeat:
	page = find_get_page(mapping, offset);
	if (page) {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		// lock_page(page);
		/* Has the page been truncated? */
		// if (unlikely(page->mapping != mapping)) {
		// 	unlock_page(page);
		// 	page_cache_release(page);
		// 	goto repeat;
		// }
		// VM_BUG_ON(page->index != offset);
	}
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return page;
}

int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
		pgoff_t offset, gfp_t gfp_mask)
{
	int error;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	// VM_BUG_ON(!PageLocked(page));

	// error = mem_cgroup_cache_charge(page, current->mm,
	// 				gfp_mask & GFP_RECLAIM_MASK);
	// if (error)
	// 	goto out;

	// error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
	// if (error == 0) {
		// page_cache_get(page);
		page->mapping = mapping;
		page->index = offset;

		// spin_lock_irq(&mapping->tree_lock);
		error = radix_tree_insert(&mapping->page_tree, offset, page);
		if (!error) {
			printf("this is %s(): %d\r\n", __func__, __LINE__);
			mapping->nrpages++;
			// __inc_zone_page_state(page, NR_FILE_PAGES);
			// if (PageSwapBacked(page))
				// __inc_zone_page_state(page, NR_SHMEM);
			// spin_unlock_irq(&mapping->tree_lock);
		} else {
			printf("this is %s(): %d\r\n", __func__, __LINE__);
			page->mapping = NULL;
			// spin_unlock_irq(&mapping->tree_lock);
			// mem_cgroup_uncharge_cache_page(page);
			// page_cache_release(page);
		}
		// radix_tree_preload_end();
	// } else {
		// mem_cgroup_uncharge_cache_page(page);
	// }
out:
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return error;
}

int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
				pgoff_t offset, gfp_t gfp_mask)
{
	int ret;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	/*
	 * Splice_read and readahead add shmem/tmpfs pages into the page cache
	 * before shmem_readpage has a chance to mark them as SwapBacked: they
	 * need to go on the active_anon lru below, and mem_cgroup_cache_charge
	 * (called in add_to_page_cache) needs to know where they're going too.
	 */
	// if (mapping_cap_swap_backed(mapping))
	// 	SetPageSwapBacked(page);

	ret = add_to_page_cache(page, mapping, offset, gfp_mask);
	// if (ret == 0) {
	// 	if (page_is_file_cache(page))
	// 		lru_cache_add_file(page);
	// 	else
	// 		lru_cache_add_active_anon(page);
	// }
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return ret;
}

static void do_generic_file_read(struct file *filp, loff_t *ppos,
		read_descriptor_t *desc, read_actor_t actor)
{
	struct address_space *mapping = filp->f_mapping;
	struct inode *inode = mapping->host;
	struct file_ra_state *ra = &filp->f_ra;
	pgoff_t index;
	pgoff_t last_index;
	pgoff_t prev_index;
	unsigned long offset;      /* offset into pagecache page */
	unsigned int prev_offset;
	int error;

	printf("this is %s(): %d >>> *ppos = %d\r\n", __func__, __LINE__, *ppos);

	// *ppos = 0;

	index = *ppos >> PAGE_CACHE_SHIFT;
	prev_index = ra->prev_pos >> PAGE_CACHE_SHIFT;
	prev_offset = ra->prev_pos & (PAGE_CACHE_SIZE-1);
	last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
	offset = *ppos & ~PAGE_CACHE_MASK;

	printf("this is %s(): %d >>> index = %d\r\n", __func__, __LINE__, index);

	for (;;) {
		printf("this is %s(): %d >>> index = %d\r\n", __func__, __LINE__, index);
		struct page *page;
		pgoff_t end_index;
		loff_t isize;
		unsigned long nr, ret;

		// cond_resched();
find_page:
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		page = find_get_page(mapping, index);
		if (!page) {
			// page_cache_sync_readahead(mapping,
			// 		ra, filp,
			// 		index, last_index - index);
			// page = find_get_page(mapping, index);
			// if (unlikely(page == NULL))
				goto no_cached_page;
		}
		// if (PageReadahead(page)) {
		// 	page_cache_async_readahead(mapping,
		// 			ra, filp, page,
		// 			index, last_index - index);
		// }
		// if (!PageUptodate(page)) {
		// 	if (inode->i_blkbits == PAGE_CACHE_SHIFT ||
		// 			!mapping->a_ops->is_partially_uptodate)
		// 		goto page_not_up_to_date;
		// 	if (!trylock_page(page))
		// 		goto page_not_up_to_date;
		// 	if (!mapping->a_ops->is_partially_uptodate(page,
		// 						desc, offset))
		// 		goto page_not_up_to_date_locked;
		// 	unlock_page(page);
		// }
page_ok:
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		/*
		 * i_size must be checked after we know the page is Uptodate.
		 *
		 * Checking i_size after the check allows us to calculate
		 * the correct value for "nr", which means the zero-filled
		 * part of the page is not copied back to userspace (unless
		 * another truncate extends the file - this is desired though).
		 */

		isize = i_size_read(inode);
		end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
		// if (!isize || index > end_index) {
		// 	page_cache_release(page);
		// 	goto out;
		// }

		/* nr is the maximum number of bytes to copy from this page */
		nr = PAGE_CACHE_SIZE;
		if (index == end_index) {
			printf("this is %s(): %d >> nr = %d\r\n", __func__, __LINE__, nr);
			nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
			printf("this is %s(): %d >> nr = %d\r\n", __func__, __LINE__, nr);
			if (nr <= offset) {
				printf("this is %s(): %d\r\n", __func__, __LINE__);
				// page_cache_release(page);
				goto out;
			}
		}
		nr = nr - offset;

		/* If users can be writing to this page using arbitrary
		 * virtual addresses, take care about potential aliasing
		 * before reading the page on the kernel side.
		 */
		// if (mapping_writably_mapped(mapping))
		// 	flush_dcache_page(page);

		/*
		 * When a sequential read accesses a page several times,
		 * only mark it as accessed the first time.
		 */
		// if (prev_index != index || offset != prev_offset)
		// 	mark_page_accessed(page);
		prev_index = index;

		/*
		 * Ok, we have the page, and it's up-to-date, so
		 * now we can copy it to user space...
		 *
		 * The actor routine returns how many bytes were actually used..
		 * NOTE! This may not be the same as how much of a user buffer
		 * we filled up (we may be padding etc), so we can only update
		 * "pos" here (the actor routine has to update the user buffer
		 * pointers and the remaining count).
		 */
		// printf("this is %s(): %d >>> ret = %d, nr = %d, desc->count = %d\r\n", __func__, __LINE__, ret, nr, desc->count);
		ret = actor(desc, page, offset, nr);
		offset += ret;
		index += offset >> PAGE_CACHE_SHIFT;
		offset &= ~PAGE_CACHE_MASK;
		prev_offset = offset;

		printf("this is %s(): %d >>> ret = %d, nr = %d, desc->count = %d, offset = %d, index = %d\r\n", __func__, __LINE__, 
						ret, nr, desc->count, offset, index);

		// page_cache_release(page);
		if (ret == nr && desc->count)
			continue;
		goto out;

// page_not_up_to_date:
// 		/* Get exclusive access to the page ... */
// 		error = lock_page_killable(page);
// 		if (unlikely(error))
// 			goto readpage_error;

// page_not_up_to_date_locked:
// 		/* Did it get truncated before we got the lock? */
// 		if (!page->mapping) {
// 			unlock_page(page);
// 			page_cache_release(page);
// 			continue;
// 		}

// 		/* Did somebody else fill it already? */
// 		if (PageUptodate(page)) {
// 			unlock_page(page);
// 			goto page_ok;
// 		}

readpage:
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		/* Start the actual read. The read will unlock the page. */
		error = mapping->a_ops->readpage(filp, page);
		// if (unlikely(error)) {
		// 	if (error == AOP_TRUNCATED_PAGE) {
		// 		page_cache_release(page);
		// 		goto find_page;
		// 	}
		// 	goto readpage_error;
		// }

		// if (!PageUptodate(page)) {
		// 	error = lock_page_killable(page);
		// 	if (unlikely(error))
		// 		goto readpage_error;
		// 	if (!PageUptodate(page)) {
		// 		if (page->mapping == NULL) {
		// 			/*
		// 			 * invalidate_inode_pages got it
		// 			 */
		// 			unlock_page(page);
		// 			page_cache_release(page);
		// 			goto find_page;
		// 		}
		// 		unlock_page(page);
		// 		shrink_readahead_size_eio(filp, ra);
		// 		error = -EIO;
		// 		goto readpage_error;
		// 	}
		// 	unlock_page(page);
		// }

		goto page_ok;

readpage_error:
		/* UHHUH! A synchronous read error occurred. Report it */
		desc->error = error;
		// page_cache_release(page);
		goto out;

no_cached_page:
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		/*
		 * Ok, it wasn't cached, so we need to create a new
		 * page..
		 */
		page = page_cache_alloc_cold(mapping);
		if (!page) {
			desc->error = -ENOMEM;
			goto out;
		}
		error = add_to_page_cache_lru(page, mapping,
						index, GFP_KERNEL);
		if (error) {
			printf("this is %s(): %d\r\n", __func__, __LINE__);
			// page_cache_release(page);
			if (error == -EEXIST)
				goto find_page;
			desc->error = error;
			goto out;
		}
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		goto readpage;
	}

out:
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	ra->prev_pos = prev_index;
	ra->prev_pos <<= PAGE_CACHE_SHIFT;
	ra->prev_pos |= prev_offset;

	*ppos = ((loff_t)index << PAGE_CACHE_SHIFT) + offset;
	// file_accessed(filp);
}

int file_read_actor(read_descriptor_t *desc, struct page *page,
			unsigned long offset, unsigned long size)
{
	char *kaddr;
	unsigned long left, count = desc->count;

	if (size > count)
		size = count;

	/*
	 * Faults on the destination of a read are common, so do it before
	 * taking the kmap.
	 */
	// if (!fault_in_pages_writeable(desc->arg.buf, size)) {
	// 	kaddr = kmap_atomic(page, KM_USER0);
	// 	left = __copy_to_user_inatomic(desc->arg.buf,
	// 					kaddr + offset, size);
	// 	kunmap_atomic(kaddr, KM_USER0);
	// 	if (left == 0)
	// 		goto success;
	// }

	/* Do it the slow way */
	// kaddr = kmap(page);
	kaddr = page_address(page);
	// left = __copy_to_user(desc->arg.buf, kaddr + offset, size);
	memcpy(desc->arg.buf, kaddr + offset, size);
	left = 0;	
	// kunmap(page);

	if (left) {
		size -= left;
		desc->error = -EFAULT;
	}
success:
	desc->count = count - size;
	desc->written += size;
	desc->arg.buf += size;
	return size;
}

ssize_t generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
		unsigned long nr_segs, loff_t pos)
{
	struct file *filp = iocb->ki_filp;
	ssize_t retval;
	unsigned long seg;
	size_t count;
	loff_t *ppos = &iocb->ki_pos;
	
	// *ppos = 0;

	printf("this is %s(): %d >>> *ppos = %d\r\n", __func__, __LINE__, *ppos);

	count = 0;
	// retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
	// if (retval)
	// 	return retval;

	/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
	// if (filp->f_flags & O_DIRECT) {
	// 	loff_t size;
	// 	struct address_space *mapping;
	// 	struct inode *inode;

	// 	mapping = filp->f_mapping;
	// 	inode = mapping->host;
	// 	if (!count)
	// 		goto out; /* skip atime */
	// 	size = i_size_read(inode);
	// 	if (pos < size) {
	// 		retval = filemap_write_and_wait_range(mapping, pos,
	// 				pos + iov_length(iov, nr_segs) - 1);
	// 		if (!retval) {
	// 			retval = mapping->a_ops->direct_IO(READ, iocb,
	// 						iov, pos, nr_segs);
	// 		}
	// 		if (retval > 0)
	// 			*ppos = pos + retval;
	// 		if (retval) {
	// 			file_accessed(filp);
	// 			goto out;
	// 		}
	// 	}
	// }

	for (seg = 0; seg < nr_segs; seg++) {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		read_descriptor_t desc;

		desc.written = 0;
		desc.arg.buf = iov[seg].iov_base;
		desc.count = iov[seg].iov_len;
		if (desc.count == 0)
			continue;
		desc.error = 0;
		do_generic_file_read(filp, ppos, &desc, file_read_actor);
		retval += desc.written;
		if (desc.error) {
			retval = retval ?: desc.error;
			break;
		}
		if (desc.count > 0)
			break;
	}
	printf("this is %s(): %d\r\n", __func__, __LINE__);
out:
	return retval;
}

static int page_cache_read(struct file *file, pgoff_t offset)
{
	struct address_space *mapping = file->f_mapping;
	struct page *page; 
	int ret;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	// do {
		page = page_cache_alloc_cold(mapping);
		if (!page)
			return -ENOMEM;

		printf("this is %s(): %d\r\n", __func__, __LINE__);

		ret = add_to_page_cache_lru(page, mapping, offset, GFP_KERNEL);
		if (ret == 0)
			ret = mapping->a_ops->readpage(file, page);
		else if (ret == -EEXIST)
			ret = 0; /* losing race to add is OK */

		// page_cache_release(page);

	// } while (ret == AOP_TRUNCATED_PAGE);
	printf("this is %s(): %d\r\n", __func__, __LINE__);
		
	return ret;
}

int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
	int error;
	struct file *file = vma->vm_file;
	struct address_space *mapping = file->f_mapping;
	struct file_ra_state *ra = &file->f_ra;
	struct inode *inode = mapping->host;
	pgoff_t offset = vmf->pgoff;
	struct page *page;
	pgoff_t size;
	int ret = 0;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
	if (offset >= size)
		return VM_FAULT_SIGBUS;

	/*
	 * Do we have something in the page cache already?
	 */
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	page = find_get_page(mapping, offset);
	if (page) {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		/*
		 * We found the page, so try async readahead before
		 * waiting for the lock.
		 */
		// do_async_mmap_readahead(vma, ra, file, page, offset);
		// lock_page(page);

		/* Did it get truncated? */
		// if (unlikely(page->mapping != mapping)) {
			// unlock_page(page);
			// put_page(page);
			// goto no_cached_page;
		// }
	} else {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		/* No page in the page cache at all */
		// do_sync_mmap_readahead(vma, ra, file, offset);
		// count_vm_event(PGMAJFAULT);
		// ret = VM_FAULT_MAJOR;
retry_find:
		page = find_lock_page(mapping, offset);
		if (!page)
			goto no_cached_page;
	}

	/*
	 * We have a locked page in the page cache, now we need to check
	 * that it's up-to-date. If not, it is going to be due to an error.
	 */
	// if (unlikely(!PageUptodate(page)))
	// 	goto page_not_uptodate;

	/*
	 * Found the page and have a reference on it.
	 * We must recheck i_size under page lock.
	 */
	size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
	if (offset >= size) {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		// unlock_page(page);
		// page_cache_release(page);
		return VM_FAULT_SIGBUS;
	}

	printf("this is %s(): %d\r\n", __func__, __LINE__);
	ra->prev_pos = (loff_t)offset << PAGE_CACHE_SHIFT;
	vmf->page = page;
	return ret | VM_FAULT_LOCKED;

no_cached_page:
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	/*
	 * We're only likely to ever get here if MADV_RANDOM is in
	 * effect.
	 */
	error = page_cache_read(file, offset);

	printf("this is %s(): %d\r\n", __func__, __LINE__);
	/*
	 * The page we want has now been added to the page cache.
	 * In the unlikely event that someone removed it in the
	 * meantime, we'll just come back here and read it again.
	 */
	if (error >= 0)
		goto retry_find;

	printf("this is %s(): %d\r\n", __func__, __LINE__);
	/*
	 * An error return from page_cache_read can result if the
	 * system is low on memory, or a problem occurs while trying
	 * to schedule I/O.
	 */
	if (error == -ENOMEM)
		return VM_FAULT_OOM;
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return VM_FAULT_SIGBUS;

// page_not_uptodate:
	/*
	 * Umm, take care of errors if the page isn't up-to-date.
	 * Try to re-read it _once_. We do this synchronously,
	 * because there really aren't any performance issues here
	 * and we need to check for errors.
	 */
	// ClearPageError(page);
	// error = mapping->a_ops->readpage(file, page);
	// if (!error) {
	// 	wait_on_page_locked(page);
	// 	if (!PageUptodate(page))
	// 		error = -EIO;
	// }
	// page_cache_release(page);

	// if (!error || error == AOP_TRUNCATED_PAGE)
	// 	goto retry_find;

	// /* Things didn't work out. Return zero to tell the mm layer so. */
	// shrink_readahead_size_eio(file, ra);
	// return VM_FAULT_SIGBUS;
}

const struct vm_operations_struct generic_file_vm_ops = {
	.fault		= filemap_fault,
};

int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
{
	struct address_space *mapping = file->f_mapping;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	if (!mapping->a_ops->readpage)
		return -ENOEXEC;
	// file_accessed(file);
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	vma->vm_ops = &generic_file_vm_ops;
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	// vma->vm_flags |= VM_CAN_NONLINEAR;
	return 0;
}

int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
{
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	// if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
	// 	return -EINVAL;
	return generic_file_mmap(file, vma);
}

void iov_iter_advance(struct iov_iter *i, size_t bytes)
{
	BUG_ON(i->count < bytes);

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	if (i->nr_segs == 1) {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		i->iov_offset += bytes;
		i->count -= bytes;
	} else {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		const struct iovec *iov = i->iov;
		size_t base = i->iov_offset;

		/*
		 * The !iov->iov_len check ensures we skip over unlikely
		 * zero-length segments (without overruning the iovec).
		 */
		while (bytes || i->count && !iov->iov_len) {
			int copy;

			copy = min(bytes, iov->iov_len - base);
			BUG_ON(!i->count || i->count < copy);
			i->count -= copy;
			bytes -= copy;
			base += copy;
			if (iov->iov_len == base) {
				iov++;
				base = 0;
			}
		}
		i->iov = iov;
		i->iov_offset = base;
	}
	printf("this is %s(): %d\r\n", __func__, __LINE__);
}

struct page *grab_cache_page_write_begin(struct address_space *mapping,
					pgoff_t index, unsigned flags)
{
	int status;
	struct page *page;
	gfp_t gfp_notmask = 0;
	// if (flags & AOP_FLAG_NOFS)
	// 	gfp_notmask = __GFP_FS;
repeat:
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	page = find_lock_page(mapping, index);
	if (page)
		return page;

	page = __page_cache_alloc(mapping_gfp_mask(mapping) & ~gfp_notmask);
	if (!page)
		return NULL;
	status = add_to_page_cache_lru(page, mapping, index,
						GFP_KERNEL & ~gfp_notmask);
	if (status) {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		// page_cache_release(page);
		if (status == -EEXIST)
			goto repeat;
		return NULL;
	}
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return page;
}

size_t iov_iter_copy_from_user_atomic(struct page *page,
		struct iov_iter *i, unsigned long offset, size_t bytes)
{
	char *kaddr;
	size_t copied;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	// BUG_ON(!in_atomic());
	kaddr = kmap_atomic(page, KM_USER0);
	// kaddr = page_address(page);
	if (i->nr_segs == 1) {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		int left;
		char *buf = i->iov->iov_base + i->iov_offset;
		// left = __copy_from_user_inatomic(kaddr + offset, buf, bytes);
		memcpy(kaddr + offset, buf, bytes);
		left = 0;	
		copied = bytes - left;
	} else {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		// copied = __iovec_copy_from_user_inatomic(kaddr + offset,
		// 				i->iov, i->iov_offset, bytes);
	}
	kunmap_atomic(kaddr, KM_USER0);

	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return copied;
}

static ssize_t generic_perform_write(struct file *file,
				struct iov_iter *i, loff_t pos)
{
	struct address_space *mapping = file->f_mapping;
	const struct address_space_operations *a_ops = mapping->a_ops;
	long status = 0;
	ssize_t written = 0;
	unsigned int flags = 0;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	/*
	 * Copies from kernel address space cannot fail (NFSD is a big user).
	 */
	// if (segment_eq(get_fs(), KERNEL_DS))
	// 	flags |= AOP_FLAG_UNINTERRUPTIBLE;

	do {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		struct page *page;
		pgoff_t index;		/* Pagecache index for current page */
		unsigned long offset;	/* Offset into pagecache page */
		unsigned long bytes;	/* Bytes to write to page */
		size_t copied;		/* Bytes copied from user */
		void *fsdata;

		offset = (pos & (PAGE_CACHE_SIZE - 1));
		index = pos >> PAGE_CACHE_SHIFT;
		bytes = min_t(unsigned long, PAGE_CACHE_SIZE - offset,
						iov_iter_count(i));

again:

		/*
		 * Bring in the user page that we will copy from _first_.
		 * Otherwise there's a nasty deadlock on copying from the
		 * same page as we're writing to, without it being marked
		 * up-to-date.
		 *
		 * Not only is this an optimisation, but it is also required
		 * to check that the address is actually valid, when atomic
		 * usercopies are used, below.
		 */
		// if (unlikely(iov_iter_fault_in_readable(i, bytes))) {
		// 	status = -EFAULT;
		// 	break;
		// }

		status = a_ops->write_begin(file, mapping, pos, bytes, flags,
						&page, &fsdata);
		if (status)
			break;

		// pagefault_disable();
		copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);
		// pagefault_enable();
		// flush_dcache_page(page);

		// mark_page_accessed(page);
		status = a_ops->write_end(file, mapping, pos, bytes, copied,
						page, fsdata);
		if (status < 0)
			break;
		copied = status;

		// cond_resched();

		iov_iter_advance(i, copied);
		// if (unlikely(copied == 0)) {
		// 	/*
		// 	 * If we were unable to copy any data at all, we must
		// 	 * fall back to a single segment length write.
		// 	 *
		// 	 * If we didn't fallback here, we could livelock
		// 	 * because not all segments in the iov can be copied at
		// 	 * once without a pagefault.
		// 	 */
		// 	bytes = min_t(unsigned long, PAGE_CACHE_SIZE - offset,
		// 				iov_iter_single_seg_count(i));
		// 	goto again;
		// }
		pos += copied;
		written += copied;

		// balance_dirty_pages_ratelimited(mapping);

	} while (iov_iter_count(i));

	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return written ? written : status;
}

ssize_t generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
		unsigned long nr_segs, loff_t pos, loff_t *ppos,
		size_t count, ssize_t written)
{
	struct file *file = iocb->ki_filp;
	struct address_space *mapping = file->f_mapping;
	ssize_t status;
	struct iov_iter i;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	iov_iter_init(&i, iov, nr_segs, count, written);
	status = generic_perform_write(file, &i, pos);

	if (status >= 0) {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		written += status;
		*ppos = pos + status;
  	}
	
	/*
	 * If we get here for O_DIRECT writes then we must have fallen through
	 * to buffered writes (block instantiation inside i_size).  So we sync
	 * the file data here, to try to honour O_DIRECT expectations.
	 */
	// if (unlikely(file->f_flags & O_DIRECT) && written)
	// 	status = filemap_write_and_wait_range(mapping,
	// 				pos, pos + written - 1);

	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return written ? written : status;
}

ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
				 unsigned long nr_segs, loff_t *ppos)
{
	struct file *file = iocb->ki_filp;
	struct address_space * mapping = file->f_mapping;
	size_t ocount;		/* original count */
	size_t count;		/* after file limit checks */
	struct inode 	*inode = mapping->host;
	loff_t		pos;
	ssize_t		written;
	ssize_t		err;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	ocount = 0;
	err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
	if (err)
		return err;

	count = ocount;
	pos = *ppos;

	// vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);

	/* We can write back this queue in page reclaim */
	// current->backing_dev_info = mapping->backing_dev_info;
	written = 0;

	// err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
	// if (err)
	// 	goto out;

	if (count == 0)
		goto out;
	printf("this is %s(): %d\r\n", __func__, __LINE__);

	// err = file_remove_suid(file);
	// if (err)
	// 	goto out;

	// file_update_time(file);

	/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
	// if (file->f_flags & O_DIRECT) {
		// loff_t endbyte;
		// ssize_t written_buffered;

		// written = generic_file_direct_write(iocb, iov, &nr_segs, pos,
		// 					ppos, count, ocount);
		// if (written < 0 || written == count)
		// 	goto out;
		// /*
		//  * direct-io write to a hole: fall through to buffered I/O
		//  * for completing the rest of the request.
		//  */
		// pos += written;
		// count -= written;
		// written_buffered = generic_file_buffered_write(iocb, iov,
		// 				nr_segs, pos, ppos, count,
		// 				written);
		// /*
		//  * If generic_file_buffered_write() retuned a synchronous error
		//  * then we want to return the number of bytes which were
		//  * direct-written, or the error code if that was zero.  Note
		//  * that this differs from normal direct-io semantics, which
		//  * will return -EFOO even if some bytes were written.
		//  */
		// if (written_buffered < 0) {
		// 	err = written_buffered;
		// 	goto out;
		// }

		// /*
		//  * We need to ensure that the page cache pages are written to
		//  * disk and invalidated to preserve the expected O_DIRECT
		//  * semantics.
		//  */
		// endbyte = pos + written_buffered - written - 1;
		// err = do_sync_mapping_range(file->f_mapping, pos, endbyte,
		// 			    SYNC_FILE_RANGE_WAIT_BEFORE|
		// 			    SYNC_FILE_RANGE_WRITE|
		// 			    SYNC_FILE_RANGE_WAIT_AFTER);
		// if (err == 0) {
		// 	written = written_buffered;
		// 	invalidate_mapping_pages(mapping,
		// 				 pos >> PAGE_CACHE_SHIFT,
		// 				 endbyte >> PAGE_CACHE_SHIFT);
		// } else {
		// 	/*
		// 	 * We don't know how much we wrote, so just return
		// 	 * the number of bytes which were direct-written
		// 	 */
		// }
	// } else {
		written = generic_file_buffered_write(iocb, iov, nr_segs,
				pos, ppos, count, written);
	// }
out:
	// current->backing_dev_info = NULL;
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return written ? written : err;
}

ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
		unsigned long nr_segs, loff_t pos)
{
	struct file *file = iocb->ki_filp;
	struct inode *inode = file->f_mapping->host;
	ssize_t ret;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	// BUG_ON(iocb->ki_pos != pos);

	// mutex_lock(&inode->i_mutex);
	ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
	// mutex_unlock(&inode->i_mutex);

	// if (ret > 0 || ret == -EIOCBQUEUED) {
	// 	ssize_t err;

	// 	err = generic_write_sync(file, pos, ret);
	// 	if (err < 0 && ret > 0)
	// 		ret = err;
	// }
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return ret;
}

struct page *find_or_create_page(struct address_space *mapping,
		pgoff_t index, gfp_t gfp_mask)
{
	struct page *page;
	int err;
repeat:
	page = find_lock_page(mapping, index);
	if (!page) {
		page = __page_cache_alloc(gfp_mask);
		if (!page)
			return NULL;
		/*
		 * We want a regular kernel memory (not highmem or DMA etc)
		 * allocation for the radix tree nodes, but we need to honour
		 * the context-specific requirements the caller has asked for.
		 * GFP_RECLAIM_MASK collects those requirements.
		 */
		err = add_to_page_cache_lru(page, mapping, index,
			(gfp_mask & GFP_RECLAIM_MASK));
		if ((err)) {
			// page_cache_release(page);
			page = NULL;
			if (err == -EEXIST)
				goto repeat;
		}
	}
	return page;
}

static struct page *__read_cache_page(struct address_space *mapping,
				pgoff_t index,
				int (*filler)(void *,struct page*),
				void *data)
{
	struct page *page;
	int err;
	printf("this is %s(): %d\r\n", __func__, __LINE__);
repeat:
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	page = find_get_page(mapping, index);
	if (!page) {
		page = page_cache_alloc_cold(mapping);
		if (!page)
			return ERR_PTR(-ENOMEM);
		err = add_to_page_cache_lru(page, mapping, index, GFP_KERNEL);
		if ((err)) {
			// page_cache_release(page);
			if (err == -EEXIST)
				goto repeat;
			/* Presumably ENOMEM for radix tree node */
			printf("this is %s(): %d\r\n", __func__, __LINE__);
			return ERR_PTR(err);
		}
		err = filler(data, page);
		if (err < 0) {
			printf("this is %s(): %d\r\n", __func__, __LINE__);
			// page_cache_release(page);
			page = ERR_PTR(err);
		}
	}
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return page;
}

struct page *read_cache_page_async(struct address_space *mapping,
				pgoff_t index,
				int (*filler)(void *,struct page*),
				void *data)
{
	struct page *page;
	int err;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

retry:
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	page = __read_cache_page(mapping, index, filler, data);
	if (IS_ERR(page))
		return page;
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	// if (PageUptodate(page))
	// 	goto out;

	// lock_page(page);
	if (!page->mapping) {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		// unlock_page(page);
		// page_cache_release(page);
		goto retry;
	}
	// if (PageUptodate(page)) {
	// 	unlock_page(page);
		goto out;
	// }
	err = filler(data, page);
	if (err < 0) {
		printf("this is %s(): %d\r\n", __func__, __LINE__);
		// page_cache_release(page);
		return ERR_PTR(err);
	}
out:
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	// mark_page_accessed(page);
	return page;
}

struct page *read_cache_page(struct address_space *mapping,
				pgoff_t index,
				int (*filler)(void *,struct page*),
				void *data)
{
	struct page *page;

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	page = read_cache_page_async(mapping, index, filler, data);
	if (IS_ERR(page))
		goto out;
	// wait_on_page_locked(page);
	// if (!PageUptodate(page)) {
	// 	page_cache_release(page);
	// 	page = ERR_PTR(-EIO);
	// }
 out:
	printf("this is %s(): %d\r\n", __func__, __LINE__);
	return page;
}
